<script type="text/javascript">

class DB{
	/** 构造函数 */
	constructor(dbName){
		this.dbName = dbName;
	}
	
	/**
	 * 选择表单
	 */
	table(tableName, keys, version){
		version = version || 10;
		this.tableName = tableName;
		
		this.request = indexedDB.open(this.dbName, version);
		
		return new Promise((resolve, reject) => {
			
			this.request.onsuccess = (event) => {
				
				
				this.db = event.target.result;
				resolve(this);
			}
			
			this.request.onupgradeneeded = (event) => {
				this.db = event.target.result;
				var objectStore;
				
				// 排列组合组装索引
				var groups = [];
				for(let i=0; i< keys.length; i++){
					var arr = []; 
					arr.push([keys[i]]);
					for(let j=0; j< groups.length; j++){
						arr.push([...groups[j], keys[i]]);
					}
					groups = groups.concat(arr);
				}
				if(!this.db.objectStoreNames.contains(tableName)){
					objectStore = this.db.createObjectStore(tableName, {keyPath: 'id', autoIncrement: true});
					groups.forEach(item => {
						var idx = item.join('_');
						objectStore.createIndex(idx, item, {unique: false});
					});
					
				}
				else{
					objectStore = this.request.transaction.objectStore(tableName);
					
					var newIndexNames = [];
					groups.forEach(item => {
						var idx = item.join('_');
						newIndexNames.push(idx);
						if(!objectStore.indexNames.contains(idx)){
							objectStore.createIndex(idx, item, {unique: false});
						}
					});
					var delIndexNames = [];
					for(var i=0; i<objectStore.indexNames.length; i++){
						var item = objectStore.indexNames.item(i);
						if(!newIndexNames.includes(item)){
							delIndexNames.push(item);
						}	
					}
					
					// 删除索引
					delIndexNames.forEach(item => {
						console.log('del:' + item);
						objectStore.deleteIndex(item);
					});
		
				}
				
			}
			
			this.request.onerror = (event) => {
				
				reject(event);
			}
		});
	}
	

	
	/**
	 * 创建索引
	 */
	index(keys){
		
		return new Promise((resolve, reject) => {
			var idx = keys.join('_');
			var transaction = this.db.transaction([this.tableName]);
			var objectStore = transaction.objectStore(this.tableName);
			objectStore.createIndex(idx, keys, {unique: false});
			
		});
		
	}
	
	/**
	 * 新增数据
	 */
	add(item){
		return new Promise((resolve, reject) => {
			var request = this.db.transaction([this.tableName], 'readwrite')
			.objectStore(this.tableName)
			.add(item);
			
			request.onsuccess = (event) => {
				resolve(event);
			}
			request.onerror = (event) => {
				reject(event);
			}
			
		});
	}
	
	/**
	 * 通过ID获取
	 */
	get(id){
		return new Promise((resolve, reject) => {
			var transaction = this.db.transaction([this.tableName]);
			var objectStore = transaction.objectStore(this.tableName);
			var request = objectStore.get(id);
			request.onsuccess = (event) => {
				resolve(event.target.result);
			}
			request.onerror = (event) => {
				reject(event);
			}
		});
	}
	
	/** 获取所有 */
	findAll(){
		return new Promise((resolve, reject) => {
			var transaction = this.db.transaction([this.tableName]);
			var objectStore = transaction.objectStore(this.tableName);
			
			var items = [];
			objectStore.openCursor().onsuccess = async (event) => {
				var cursor = event.target.result;
				if(cursor){
					
					items.push(cursor.value);
					cursor.continue();
				}
				else{
					resolve(items);
				}
				
			}
			
		});
	}

	/**
	 * 统计数量
	 */
	count(filter){
		return new Promise((resolve, reject) => {
			var keys = Object.keys(filter);
			var values = Object.values(filter);
			
			var transaction = this.db.transaction([this.tableName]);
			var objectStore = transaction.objectStore(this.tableName);
			var index = objectStore.index(keys.join('_'));
			var request = index.count(IDBKeyRange.only(values));
			request.onsuccess = (event) => {
				
				resolve(event.target.result);
			}
			
			request.onerror = (event) => {
				reject(event)
			}
			
		});
	}
	
	/**
	 * 查询列表
	 */
	findList(filter, page = 1, size = 10){
		return new Promise((resolve, reject) => {
			var keys = Object.keys(filter);
			var values = Object.values(filter);
			
			var transaction = this.db.transaction([this.tableName]);
			var objectStore = transaction.objectStore(this.tableName);
			var index = objectStore.index(keys.join('_'));
			var items = [];
			var offset = (page - 1) * size;
			var advance = false;
			index.openCursor(IDBKeyRange.only(values), 'prev').onsuccess = async (event) => {
				var cursor = event.target.result;
				
				if(cursor){
					if(advance || offset == 0){
						advance = true;
						
						items.push(cursor.value);
						if(items.length < size){
							cursor.continue();
						}
						else{
							resolve(items);
						}
					}
					else{
						advance = true;
						cursor.advance(offset);
					}
					
				}
				else{
					resolve(items);
				}
				
			}
			
		});
	}
}

var filter = {age: 24};
var db = new DB('TTDB');
db.table('person', ['name', 'age'], 1)
.then(() => {
	// var names = ['赵一', '钱二', '张三', '李四','王五','孙六','曾七']
	// for(var i=0; i< 100; i++){
	// 	var random = Math.ceil(Math.random() * 7)
	// 	db.add({name: names[random], age: 20 + Math.ceil(Math.random() * 10), email: 'zhangsan' + Math.ceil(Math.random() * 7) +'@email.com'})
	// }	
	
})
.then(()=>{
	return db.get(11);
}).then(res => {
	console.log(res);
}).then(() => {
	return db.findAll();
}).then(res =>{
	//console.log(res);
})
.then(()=>{
	return db.count(filter)
})
.then(res => {
	console.log(res);
})
.then(() =>{
	return db.findList(filter)
}).then(res =>{
	console.log(res);
});



</script>